/**
 * NodeDescriptor.java
 * ************************** 
 * @date Mar 18, 2011
 * @author Michele Tamburini
 * 
 * **************************
 */
package gossipServices.basic.nodeDescriptors;

import java.net.InetAddress;


/**
 * Description:
 * This is a basic implementation of the NodeDesciptor interface.
 * It provides all (and only) the required methods to access 
 * the variables of a NodeDescriptor. 
 * There aren't any set methods, and a ConcreteNodeDescriptor
 * can be only created by constructors.
 * Variables:
 *  	age : Integer - the age of the node descriptor
 *   	nodeName : String - the name set for the peer
 *   	address : InetAddress - the address of the node's host machine
 *   	ID : automatically generated.
 * The NodeID is generated from the hashCode of the nodeName. 
 * A good strategy sets each node with a unique nodeName among all the others 
 * in order to avoid mistakes.
 * The length of the nodeName is adjusted to fit the ID_LEGTH. 
 * If its size is shorted then a string of WILD_CHAR is added.
 * If its size is longer then is simply truncated.
 *
 */
public class ConcreteNodeDescriptor implements NodeDescriptor,
		PssNodeDescriptor {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	protected Integer age;
	protected String nodeName;
	protected InetAddress address;
	protected Integer ID;

		
	/**
	 * Specify the name and the actual age of the NodeDescriptor.
	 * @param name : String the name of the node
	 * @param age : int current age of the node (generally you will need it to 0)
	 */
	public ConcreteNodeDescriptor(String name, int age){
		this.age = new Integer(age);
//		this.nodeName = name;
		setName(name);
		createID();
	}
	
	/**
	 * It sets the local nodeName with the input parameter 'name'.
	 * Then it verify the length of the string and set it to
	 * the value of ID_LENGTH. So the function truncates the name if it is 
	 * too long, or fills the remaining with the WILD_CHAR,  
	 * @param name
	 */
	private void setName(String name) {
//		this.nodeName = name;
		this.nodeName = adjustNodeName(name);
	}
	
	public static String adjustNodeName(String inputName){
		String outputName = new String(inputName);
		int l = outputName.length();
		if(l < ID_LENGTH){
			for(int i=l; i<ID_LENGTH; i++ ){
				outputName += WILD_CHAR;
			}
		}else if(l > ID_LENGTH){
			outputName = outputName.substring(0, ID_LENGTH);
		}
		return outputName;
	}
	
	/**
	 * It set the NodeDescriptor ID using the current nodeName.
	 * Be sure to set the nodeName before the calling of this function.
	 * @param inputName
	 */
	private void createID() {
		ID = new Integer(nodeName.hashCode());
	}

	/**
	 * Create the NodeDescriptor only by specifying its name.
	 * @param name
	 */
	public ConcreteNodeDescriptor(String name){
		this.age = new Integer(0);
//		this.nodeName = name;
		setName(name);
		createID();
	}
	
	/**
	 * Builds a new ConcreteNodeDescripto from another one in input.
	 * @param inputNode : ConcreteNodeDescriptor
	 */
	public ConcreteNodeDescriptor(ConcreteNodeDescriptor inputNode){
		this.age = inputNode.getAge();
		this.address = inputNode.getNodeAddress();
		this.nodeName = inputNode.getNodeName();
		this.ID = inputNode.getNodeID();
	}
	
	/**
	 * Build a ConcreteNodeDescriptor from all its input parameters
	 * @param nodeName : String the name of the Node
	 * @param nodeAddress : InetAddress the address of the host machine
	 * @param age : Integer the actual age of the NodeDescriptor
	 */
	public ConcreteNodeDescriptor(String nodeName, InetAddress nodeAddress,
			Integer age) {
		this.age = age;
		this.address = nodeAddress;
//		this.nodeName = nodeName;
		setName(nodeName);
		createID();
	}

	/**
	 * @param p
	 */
	public ConcreteNodeDescriptor(NodeDescriptor p) {
		this.nodeName = p.getNodeName();
		this.address = p.getNodeAddress();
		this.ID = p.getNodeID();
	}
	
	public ConcreteNodeDescriptor(PssNodeDescriptor p) {
		this.nodeName = p.getNodeName();
		this.address = p.getNodeAddress();
		this.age = p.getAge();
		this.ID = p.getNodeID();
	}

	@Override
	public Integer getAge() {
		return age;
	}

	@Override
	public void increaseAge() {
//		this.age = new Integer(age.intValue()+1);
		age++;
	}
	
	@Override
	public String getNodeName() {
		return nodeName;
	}
	
	@Override
	public InetAddress getNodeAddress() {
		return address;
	}
		
	
	public boolean isFresh(ConcreteNodeDescriptor o){
		return age.intValue() < o.getAge().intValue();
	}
	
	public boolean equals(Object o){
		return this.nodeName.equals( ((ConcreteNodeDescriptor)o).getNodeName() );
	}
	
	public String toString(){
		return ID+" "+nodeName+" "+address+" "+age;
	}

	@Override
	public Integer getNodeID() {
		return ID;
	}

//	@Override
//	public int compareTo(NodeDescriptor o) {
////		int thisAge = this.age;
////		int otherAge = o.getAge();
////		return ( (thisAge < otherAge) ? -1 : (thisAge == otherAge ? 0 : 1 )) ;
//		return age.compareTo(o.getAge());
//	}

		
//	public Object clone(){
//		NodeDescriptor ret = null;
//		try{
//			ret = (NodeDescriptor) super.clone();
//			ret.nodeName = new String(this.nodeName);
//			ret.age = new Integer(age);
//			ret.ip = this.ip;
//		}catch(CloneNotSupportedException e){
//			e.printStackTrace();
//		}catch(Exception e){
//			e.printStackTrace();
//		}
//		
//		return ret;
//		
//	}

}
